package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

// WsChatClient 聊天客户端
type WsChatClient struct {
	conn     *websocket.Conn // 用户websocket连接
	nickname string          // 用户昵称
}

var (
	wsUpgrader    = websocket.Upgrader{}
	wsChatClients = make(map[*WsChatClient]bool) // webscoket聊天客户端
	chatTick      *time.Ticker                   // 聊天定时广播
)

func main() {
	chatBroadcastServe() // 调用聊天室广播服务

	// 开始创建http服务
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "ws.html", nil)
	})

	r.GET("/ws", func(c *gin.Context) {
		func(w http.ResponseWriter, r *http.Request) {
			conn, err := wsUpgrader.Upgrade(w, r, nil)
			if err != nil {
				// print err
				fmt.Printf("/ws Failed to set websocket upgrade: %+v\n", err)
				return
			}

			for {
				t, msg, err := conn.ReadMessage()
				if err != nil {
					break
				}

				conn.WriteMessage(t, msg)
			}
		}(c.Writer, c.Request)
	})

	// 聊天室页面
	r.GET("/chat", func(c *gin.Context) {
		c.HTML(http.StatusOK, "chat.html", nil)
	})

	// 聊天室服务
	r.GET("/chat-serve", func(c *gin.Context) {
		nickname := c.Query("nickname")

		// webscoket处理器
		func(w http.ResponseWriter, r *http.Request) {
			conn, err := wsUpgrader.Upgrade(w, r, nil)
			if err != nil {
				// print err
				fmt.Printf("/chat Failed to set websocket upgrade: %+v\n", err)
				return
			}

			wsk := &WsChatClient{conn: conn, nickname: nickname} // 客户端指针作为map的key

			defer func() {
				conn.Close()
				delete(wsChatClients, wsk) // 删除关闭的客户端

				fmt.Printf("new wsChatClients: %+v\n", wsChatClients)
			}()

			// 加入连接
			wsChatClients[wsk] = true

			for {
				t, msg, err := conn.ReadMessage()
				if err != nil {
					break
				}

				// 给每个连接的客户端发送消息
				for k, v := range wsChatClients {
					if v {
						(*k).conn.WriteMessage(t, msg)
					}
				}
			}

		}(c.Writer, c.Request)
	})

	r.Run(":1234")
}

// 聊天室广播服务
func chatBroadcastServe() {
	// 聊天广播定时器
	chatTick := time.NewTicker(60 * time.Second) // 每60s执行一次

	// 执行广播任务
	go func() {
		for {
			select {
			case t := <-chatTick.C:
				// 开启协程去处理任务
				go func() {
					fmt.Printf("/chat 定时广播 [%+v]\n", t)
					for k, v := range wsChatClients {
						if v {
							k.conn.WriteMessage(websocket.TextMessage, []byte("[系统消息]：请大家文明聊天"))
						}
					}
				}()
			}
		}
	}()
}
